Home:ALL Converter>Implementing MVVM with ArcGIS Runtime local server

Implementing MVVM with ArcGIS Runtime local server

Ask Time:2018-11-22T04:14:12         Author:Mona Coder

Json Formatter

I am trying to setup a ESRI Local Server for displaying .mpk. I have a Model like

public class Model
{
    private string basemapLayerUri = "http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer";
    private string mapPackage = "D:\\App\\Data\\Canada.mpk";
    public Model() { }

    public string BasemapLayerUri
    {
        get { return this.basemapLayerUri; }
        set
        {
            if (value != this.basemapLayerUri)
            {
                this.basemapLayerUri = value;
            }
        }
    }

    public string MapPackage
    {
        get { return this.mapPackage; }
        set
        {
            if (value != this.mapPackage)
            {
                this.mapPackage = value;
            }
        }
    }
}

in ViewModel.cs Class I have

public class ViewModel : INotifyPropertyChanged
{
    public Model myModel { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;

    public ViewModel()
    {
        myModel = new Model();
        this.CreateLocalServiceAndDynamicLayer();
    }

    public string BasemapUri
    {
        get { return myModel.BasemapLayerUri; }
        set
        {
            this.myModel.BasemapLayerUri = value;
            OnPropertyChanged("BasemapUri");
        }
    }

    public async void CreateLocalServiceAndDynamicLayer()
    {
        LocalMapService localMapService = new LocalMapService(this.MAPKMap);
        await localMapService.StartAsync();

        ArcGISDynamicMapServiceLayer arcGISDynamicMapServiceLayer = new ArcGISDynamicMapServiceLayer()
        {
            ID = "mpklayer",
            ServiceUri = localMapService.UrlMapService,
        };

        //myModel.Map.Layers.Add(arcGISDynamicMapServiceLayer);
    }

    public string MAPKMap
    {
        get { return myModel.MapPackage; }
        set
        {
            this.myModel.MapPackage = value;
            OnPropertyChanged("MAPKMap");
        }
    }

    protected void OnPropertyChanged([CallerMemberName] string member = "")
    {
        var eventHandler = PropertyChanged;
        if (eventHandler != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(member));
        }
    }
}

As you can see I am trying to implement the local server and dynamic layer in ViewModel.cs like

public async void CreateLocalServiceAndDynamicLayer()
{
    LocalMapService localMapService = new LocalMapService(this.MAPKMap);
    await localMapService.StartAsync();

    ArcGISDynamicMapServiceLayer arcGISDynamicMapServiceLayer = new ArcGISDynamicMapServiceLayer()
    {
        ID = "mpklayer",
        ServiceUri = localMapService.UrlMapService,
    };

    //myModel.Map.Layers.Add(arcGISDynamicMapServiceLayer);
}

but I do not know how to bind this service to the Model ? I tried

myModel.Map.Layers.Add(arcGISDynamicMapServiceLayer);

but as you know the myModel doesn't have any Map object.

Update

using M_PK2.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Esri.ArcGISRuntime.LocalServices;
using Esri.ArcGISRuntime.Controls;
using Esri.ArcGISRuntime.Layers;

namespace M_PK2.ViewModels
{
    class ViewModel : ViewModelBase
    {
        private readonly LocalMapService localMapService;
        private readonly Model myModel;
        private LayerCollection layers;

        public ViewModel()
        {
            myModel = new Model();
            layers = new LayerCollection();
            localMapService = new LocalMapService(myModel.MapPackage);
            starting += onStarting;
            starting(this, EventArgs.Empty);
        }

        private event EventHandler starting = delegate { };
        private async void onStarting(object sender, EventArgs args)
        {
            starting -= onStarting; //optional

            // the following runs on background thread
            await localMapService.StartAsync();

            // returned to the UI thread

            var serviceLayer = new ArcGISDynamicMapServiceLayer()
            {
                ID = "mpklayer",
                ServiceUri = localMapService.UrlMapService,
            };

            Layers.Add(serviceLayer);
            OnPropertyChanged(nameof(Layers)); //Notify UI
        }


        public LayerCollection Layers
        {
            get
            {
                return layers;
            }
        }
    }
    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        protected void OnPropertyChanged([CallerMemberName] string member = "")
        {
            PropertyChanged(this, new PropertyChangedEventArgs(member));
        }
    }
}

Author:Mona Coder,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/53419823/implementing-mvvm-with-arcgis-runtime-local-server
Nkosi :

Avoid using async void except for event handlers, \n\nReference Async/Await - Best Practices in Asynchronous Programming\n\nIn your case you are mixing UI concerns that belong in view. The view model should expose what the view needs in order to perform its function.\n\nBecause of the async nature of the used dependency LocalMapService, you should create an async event handler to manage getting the service URI and notify the UI when that task is completed via a bound property change event.\n\nFor example\n\npublic class ViewModel : ViewModelBase {\n private readonly LocalMapService localMapService;\n private readonly Model myModel;\n private string serviceUri;\n\n public ViewModel() {\n myModel = new Model();\n localMapService = new LocalMapService(myModel.MapPackage);\n starting += onStarting;\n starting(this, EventArgs.Empty);\n }\n\n private event EventHandler starting = delegate { };\n private async void onStarting(object sender, EventArgs args) {\n starting -= onStarting; //optional\n\n // the following runs on background thread\n await localMapService.StartAsync(); \n\n // returned to the UI thread\n ServiceUri = localMapService.UrlMapService; //notifies UI\n }\n\n public string ServiceUri {\n get { return serviceUri; }\n set {\n serviceUri = value;\n OnPropertyChanged();\n }\n }\n}\n\npublic class ViewModelBase : INotifyPropertyChanged {\n public event PropertyChangedEventHandler PropertyChanged = delegate { };\n\n protected void OnPropertyChanged([CallerMemberName] string member = \"\") {\n PropertyChanged(this, new PropertyChangedEventArgs(member));\n }\n}\n\n\nThat way after the async starting of the service, the UI will get notified of the change.\n\n<!-- Add a MapView Control. -->\n<esriControls:MapView x:Name=\"MapView1\">\n\n <!-- Add a Map. -->\n <esriControls:Map>\n\n <!-- Add an ArcGISDynamicMapServiceLayer via XAML. -->\n <esriLayers:ArcGISDynamicMapServiceLayer ID=\"mpklayer\" \n ServiceUri=\"{Bind ServiceUri}\"/>\n </esriControls:Map>\n</esriControls:MapView>\n\n\nIf the goal is to be able to manipulate multiple layers then I would suggest binding to the Map.Layers Property to be able to have direct access to the layers collection in the view model.\n\nThe view model could end up looking like\n\npublic class ViewModel : ViewModelBase {\n private readonly LocalMapService localMapService;\n private readonly Model myModel;\n private LayerCollection layers;\n\n public ViewModel() {\n myModel = new Model();\n layers = new LayerCollection();\n localMapService = new LocalMapService(myModel.MapPackage);\n starting += onStarting;\n starting(this, EventArgs.Empty);\n }\n\n private event EventHandler starting = delegate { };\n private async void onStarting(object sender, EventArgs args) {\n starting -= onStarting; //optional\n\n // the following runs on background thread\n await localMapService.StartAsync(); \n\n // returned to the UI thread\n\n var serviceLayer = new ArcGISDynamicMapServiceLayer() {\n ID = \"mpklayer\",\n ServiceUri = localMapService.UrlMapService,\n };\n\n Layers.Add(serviceLayer);\n }\n\n public LayerCollection Layers {\n get {\n return layers;\n }\n }\n}\n\n\nAnd the view \n\n<!-- Add a MapView Control. -->\n<esriControls:MapView x:Name=\"MapView1\">\n\n <!-- Add a Map. with layers via binding-->\n <esriControls:Map Layers=\"{Bind Layers, Mode=OneWay}\" />\n</esriControls:MapView>\n\n\nYou can now manipulate layers via code as needed",
2018-12-07T10:34:19
yy